/* 
 * File:   main.c
 * Author: Julian
 *
 * Created on 24. Januar 2014, 15:02
 */

/*
 * I2C Slave
 * #17 SCL1, RB8 (#15 ASCL, RB6)
 * #18 SDA1, RB9 (#14 ASDA, RB5)
 * #07 SCL2, RB3
 * #06 SDA2, RB2
 */

/*
 * Register Map
 *
 * SI2CxIF interrupt for slave operation
 *
 * The SI2CxIF interrupt is generated on detection of a message directed to the
 * slave, including these events:
 * > Detection of a valid device address (including general call)
 * > Request to transmit data (ACK) or to stop transmitting data (NACK)
 * > Reception of data
 */

/*
 * Detect flags:
 * I2CxSTAT.P Stop condition (auto clear)  I2CxSTAT.S Start condition (auto clear)
 * RX: DA clear, RW clear, RBF set + interrupt
 *     DA set, RBF set + n-interrupts
 * TX: DA clear, RW set, RBF set + interrupt + SCL low + I2CxTRN write + SCLREL set
 */

/* Example Syntax:                                                            */
/*                                                                            */
/* void __attribute__((interrupt,auto_psv)) <Vector Name>(void)               */
/* {                                                                          */
/*     <Clear Interrupt Flag>                                                 */
/* }                                                                          */

/*
 * I2C Address: [1010][000] 0x50 ([1001][000] 0x48,[1001][111] 0x4F)
 */

#include <xc.h>
#include <stdint.h>
#include "configuration.h"
#include "Pwm.h"
#include "Ticker.h"

volatile uint8_t trx;

void toggleLed(void);

int main(void) {
#if defined(FRCDIV)
    CLKDIVbits.RCDIV = FRCDIV;
#endif
    /* Config Periphials. */
    Pwm pwmCh1, pwmCh2, pwmCh3;
    Pwm *pwmChannels[] = { &pwmCh1, &pwmCh2, &pwmCh3 };
    int i;
    for(i = 0; i < 3; i++) { Pwm_ctor(pwmChannels[i], i, 0, 4095); }
    Pwm_setDutyCycle(pwmChannels[0], 2047);
    Pwm_setDutyCycle(pwmChannels[1], 1023);
    Pwm_setDutyCycle(pwmChannels[2], 3071);
    I2C1CON = 0x1000;
    /* Do I2C config. */
    I2C1ADD = 0x50;
    I2C1CONbits.I2CEN = 1;
    /* Enable Interrupts. */
    IFS1bits.SI2C1IF = 0; /* Clear flag. */
    IEC1bits.SI2C1IE = 1; /* Enable I2C slave interrupt. */
    /* Blinking LED. */
    TRISAbits.TRISA0 = 0;
    Ticker ledTicker;
    Ticker_ctor(&ledTicker);
    Ticker_attach(&ledTicker, &toggleLed, 1000);
    while(1) {
        /* Calculate Pi till to the end of the world. */
    }
}

void toggleLed(void) {
    LATAbits.LATA0 ^= 1;
}

void __attribute__((interrupt,auto_psv)) _SI2C1Interrupt(void) {
    if(I2C1STATbits.RBF) {
        trx = I2C1RCV;
    }
    if(I2C1STATbits.R_W && !I2C1CONbits.SCLREL) {
        I2C1TRN = trx;
        I2C1CONbits.SCLREL = 1;
    }
    IFS1bits.SI2C1IF = 0; /* Clear flag. */
}
